package com.jgit;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.*;

/**
 * Git仓库：管理仓库的核心操作
 */
public class Repository {
    private String workTree;  // 工作目录
    private String gitDir;    // .git目录
    private ObjectStore objectStore;
    private Index index;
    
    public Repository(String path) throws IOException {
        this.workTree = Paths.get(path).toAbsolutePath().normalize().toString();
        this.gitDir = Paths.get(workTree, ".git").toString();
        this.objectStore = new ObjectStore(gitDir);
        this.index = new Index(gitDir);
    }
    
    /**
     * 初始化仓库
     */
    public static Repository init(String path) throws IOException {
        Path workTreePath = Paths.get(path);
        Path gitPath = workTreePath.resolve(".git");
        
        // 创建必要的目录结构
        Files.createDirectories(gitPath.resolve("objects"));
        Files.createDirectories(gitPath.resolve("refs").resolve("heads"));
        Files.createDirectories(gitPath.resolve("refs").resolve("tags"));
        
        // 创建HEAD文件，指向master分支
        Path headFile = gitPath.resolve("HEAD");
        Files.write(headFile, "ref: refs/heads/master\n".getBytes());
        
        // 创建config文件
        Path configFile = gitPath.resolve("config");
        String config = "[core]\n" +
                        "\trepositoryformatversion = 0\n" +
                        "\tfilemode = true\n" +
                        "\tbare = false\n";
        Files.write(configFile, config.getBytes());
        
        return new Repository(path);
    }
    
    /**
     * 检查是否是Git仓库
     */
    public static boolean isGitRepository(String path) {
        Path gitPath = Paths.get(path, ".git");
        return Files.exists(gitPath) && Files.isDirectory(gitPath);
    }
    
    /**
     * 添加文件到暂存区
     */
    public void add(String filePath) throws IOException {
        Path fullPath = Paths.get(workTree, filePath);
        if (!Files.exists(fullPath)) {
            throw new IOException("File not found: " + filePath);
        }
        
        byte[] fileContent = Files.readAllBytes(fullPath);
        Blob blob = new Blob(fileContent);
        blob.calculateHash();
        
        objectStore.store(blob);
        
        // 添加到索引
        String mode = Files.isRegularFile(fullPath) ? "100644" : "40000";
        index.add(filePath, blob.getHash(), mode);
        index.save();
    }
    
    /**
     * 创建提交
     */
    public String commit(String message, String author, String committer) throws IOException {
        // 从索引构建tree对象
        Tree tree = buildTreeFromIndex();
        tree.calculateHash();
        objectStore.store(tree);
        
        // 创建commit对象
        Commit commit = new Commit();
        commit.setTreeHash(tree.getHash());
        commit.setMessage(message);
        commit.setAuthor(author);
        commit.setCommitter(committer);
        commit.setTimestamp(System.currentTimeMillis() / 1000);
        
        // 获取当前HEAD的提交作为父提交
        String currentHead = getCurrentHead();
        if (currentHead != null) {
            commit.addParent(currentHead);
        }
        
        commit.calculateHash();
        objectStore.store(commit);
        
        // 更新HEAD
        updateHead(commit.getHash());
        
        // 清空索引
        index.clear();
        index.save();
        
        return commit.getHash();
    }
    
    /**
     * 从索引构建tree对象（支持多层目录结构）
     */
    private Tree buildTreeFromIndex() throws IOException {
        // 使用树形结构组织文件
        Map<String, Object> treeStructure = new HashMap<>();
        
        for (Index.IndexEntry entry : index.getEntries().values()) {
            String[] parts = entry.getPath().split("/");
            Map<String, Object> current = treeStructure;
            
            // 遍历路径的每一部分（除了最后一部分）
            for (int i = 0; i < parts.length - 1; i++) {
                String part = parts[i];
                if (!current.containsKey(part)) {
                    current.put(part, new HashMap<String, Object>());
                }
                current = (Map<String, Object>) current.get(part);
            }
            
            // 最后一部分是文件名
            current.put(parts[parts.length - 1], entry);
        }
        
        // 递归构建tree对象
        return buildTreeRecursive(treeStructure);
    }
    
    /**
     * 递归构建tree对象
     */
    private Tree buildTreeRecursive(Map<String, Object> structure) throws IOException {
        Tree tree = new Tree();
        
        for (Map.Entry<String, Object> entry : structure.entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();
            
            if (value instanceof Index.IndexEntry) {
                // 这是一个文件
                Index.IndexEntry fileEntry = (Index.IndexEntry) value;
                tree.addEntry(new TreeEntry(fileEntry.getMode(), name, fileEntry.getHash()));
            } else if (value instanceof Map) {
                // 这是一个目录，递归构建
                @SuppressWarnings("unchecked")
                Map<String, Object> dirStructure = (Map<String, Object>) value;
                Tree dirTree = buildTreeRecursive(dirStructure);
                dirTree.calculateHash();
                objectStore.store(dirTree);
                tree.addEntry(new TreeEntry("40000", name, dirTree.getHash()));
            }
        }
        
        return tree;
    }
    
    /**
     * 获取当前HEAD指向的提交
     */
    public String getCurrentHead() throws IOException {
        Path headFile = Paths.get(gitDir, "HEAD");
        if (!Files.exists(headFile)) {
            return null;
        }
        
        String headContent = new String(Files.readAllBytes(headFile)).trim();
        if (headContent.startsWith("ref: ")) {
            String refPath = headContent.substring(5);
            Path refFile = Paths.get(gitDir, refPath);
            if (Files.exists(refFile)) {
                return new String(Files.readAllBytes(refFile)).trim();
            }
        } else {
            return headContent;
        }
        
        return null;
    }
    
    /**
     * 更新HEAD
     */
    private void updateHead(String commitHash) throws IOException {
        Path headFile = Paths.get(gitDir, "HEAD");
        String headContent = new String(Files.readAllBytes(headFile)).trim();
        
        String branchName = "master";
        if (headContent.startsWith("ref: ")) {
            String refPath = headContent.substring(5);
            if (refPath.startsWith("refs/heads/")) {
                branchName = refPath.substring(11);
            }
        }
        
        // 更新分支引用
        Path branchFile = Paths.get(gitDir, "refs", "heads", branchName);
        Files.createDirectories(branchFile.getParent());
        Files.write(branchFile, (commitHash + "\n").getBytes());
    }
    
    /**
     * 创建新分支
     */
    public void createBranch(String branchName) throws IOException {
        String currentHead = getCurrentHead();
        if (currentHead == null) {
            throw new IOException("Cannot create branch: no commits yet");
        }
        
        Path branchFile = Paths.get(gitDir, "refs", "heads", branchName);
        Files.createDirectories(branchFile.getParent());
        Files.write(branchFile, (currentHead + "\n").getBytes());
    }
    
    /**
     * 切换到分支
     */
    public void checkoutBranch(String branchName) throws IOException {
        Path branchFile = Paths.get(gitDir, "refs", "heads", branchName);
        if (!Files.exists(branchFile)) {
            throw new IOException("Branch not found: " + branchName);
        }
        
        Path headFile = Paths.get(gitDir, "HEAD");
        Files.write(headFile, ("ref: refs/heads/" + branchName + "\n").getBytes());
    }
    
    /**
     * 获取所有分支
     */
    public List<String> getBranches() throws IOException {
        List<String> branches = new ArrayList<>();
        Path headsDir = Paths.get(gitDir, "refs", "heads");
        if (Files.exists(headsDir)) {
            Files.list(headsDir).forEach(path -> {
                branches.add(path.getFileName().toString());
            });
        }
        return branches;
    }
    
    /**
     * 获取当前分支名
     */
    public String getCurrentBranch() throws IOException {
        Path headFile = Paths.get(gitDir, "HEAD");
        if (!Files.exists(headFile)) {
            return null;
        }
        
        String headContent = new String(Files.readAllBytes(headFile)).trim();
        if (headContent.startsWith("ref: refs/heads/")) {
            return headContent.substring(16);
        }
        return null;
    }
    
    public String getWorkTree() {
        return workTree;
    }
    
    public String getGitDir() {
        return gitDir;
    }
    
    public ObjectStore getObjectStore() {
        return objectStore;
    }
    
    public Index getIndex() {
        return index;
    }
}

